package com.creatapark.service;

import com.creatapark.constant.ParkConstant;
import com.creatapark.constant.ParkMetric;
import com.creatapark.constant.WeekType;
import com.creatapark.entity.DerationData;
import com.creatapark.entity.MetricEntity;
import com.creatapark.mapper.DerationDataMapper;
import com.creatapark.mapper.ParkCarByTimeMapper;
import com.creatapark.mapper.ParkSummaryMapper;
import com.creatapark.monitor.annotation.Monitor;
import com.creatapark.util.DateHelper;
import com.creatapark.vo.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ReportService
 *
 * @author Bruce01.fan
 * @date 2017/7/24
 */
@Service
public class ReportService {

    private int hours = 24;
    private long one_hour = 3600 ;

    @Autowired
    DerationDataMapper derationDataMapper;
    @Autowired
    ParkCarByTimeMapper parkCarByTimeMapper;
    @Autowired
    ParkSummaryMapper parkSummaryMapper;

    public List<TargetVo> queryParkData(Long parkId, String startDate, String endDate) {

        startDate = startDate + " 00:00";
        endDate = endDate + "23:59";

        List<TargetVo> list = new ArrayList<>();
        // 营业额
        List<MetricEntity> revenueMetricEntity = parkSummaryMapper.queryRevenue(parkId,startDate,endDate);
        int revenueTotal = revenueMetricEntity.stream().mapToInt(entity -> Integer.parseInt(entity.getMetricValue())).reduce(0,Integer::sum);
        // 车流量
        List<MetricEntity> flowMetricEntity =  parkSummaryMapper.queryFlow(parkId,startDate,endDate);
        int flowTotal = flowMetricEntity.stream().mapToInt(entity -> Integer.parseInt(entity.getMetricValue())).reduce(0,Integer::sum);
        // 订单量
        List<MetricEntity> orderMetricEntity = parkSummaryMapper.queryOrder(parkId,startDate,endDate);
        int orderTotal = orderMetricEntity.stream().mapToInt(entity -> Integer.parseInt(entity.getMetricValue())).reduce(0,Integer::sum);
        //  客单量
        int customCount = revenueTotal / orderTotal ;
        // 平均停车时长
        List<MetricEntity> avgTimeMetricEntity = parkSummaryMapper.queryAvgTime(parkId,startDate,endDate);
        OptionalDouble optionalDouble = avgTimeMetricEntity.stream().mapToInt(entity -> Integer.parseInt(entity.getMetricValue())).average();
        // 平均单价
        List<MetricEntity> avgPriceMetricEntity = parkSummaryMapper.queryAvgPrice(parkId,startDate,endDate);
        OptionalDouble optionalAvgPrice = avgPriceMetricEntity.stream().mapToInt(entity -> Integer.parseInt(entity.getMetricValue())).average();
        // 平均车位贡献
        int avgGX = revenueTotal / flowTotal;
        // 平均车位利用率

        TargetVo revenueTargetVo = new TargetVo(ParkMetric.Revenue.getMetricName(),String.valueOf(revenueTotal),ParkMetric.Revenue.getMetricId());
        TargetVo flowTargetVo = new TargetVo(ParkMetric.FLOW.getMetricName(),String.valueOf(flowTotal),ParkMetric.FLOW.getMetricId());
        TargetVo orderTargetVo = new TargetVo(ParkMetric.ORDER.getMetricName(),String.valueOf(orderTotal),ParkMetric.ORDER.getMetricId());
        TargetVo customTargetVo = new TargetVo(ParkMetric.SINGLE.getMetricName(),String.valueOf(customCount),ParkMetric.SINGLE.getMetricId());
        TargetVo avgTimeTargetVo = new TargetVo(ParkMetric.AVGTIME.getMetricName(),String.valueOf(optionalDouble.getAsDouble()),ParkMetric.AVGTIME.getMetricId());
        TargetVo avgPriceTargetVo = new TargetVo(ParkMetric.AVGPRICE.getMetricName(),String.valueOf(optionalAvgPrice.getAsDouble()),ParkMetric.AVGPRICE.getMetricId());
        TargetVo avgGXTargetVo = new TargetVo(ParkMetric.AVGPARKGX.getMetricName(),String.valueOf(avgGX),ParkMetric.AVGPARKGX.getMetricId());

        list.add(revenueTargetVo);
        list.add(flowTargetVo);
        list.add(orderTargetVo);
        list.add(customTargetVo);
        list.add(avgTimeTargetVo);
        list.add(avgPriceTargetVo);

        return list;
    }

    public PieDataVo queryPieDataByType(Long parkId, String startDate, String endDate,String typeId) {

        PieDataVo pieDataVo = new PieDataVo();
        List<MetricEntity> metricEntity = null;

        if(typeId.equals(ParkMetric.Revenue.getMetricId())){
            metricEntity = parkSummaryMapper.queryRevenue(parkId,startDate,endDate);
            pieDataVo.setTitle(ParkConstant.TITLE_FOR_PIC_REVENUE);
        }else if(typeId.equals(ParkMetric.FLOW.getMetricId())) {
            metricEntity = parkSummaryMapper.queryFlow(parkId,startDate,endDate);
            pieDataVo.setTitle(ParkConstant.TITLE_FOR_PIC_FLOW);
        }else if(typeId.equals(ParkMetric.ORDER.getMetricId())) {
            metricEntity = parkSummaryMapper.queryOrder(parkId,startDate,endDate);
            pieDataVo.setTitle(ParkConstant.TITLE_FOR_PIC_ORDER);
        }

        if(metricEntity != null) {
           List<PieVo> pieVos = metricEntity.stream().map(entity -> {
                String week = DateHelper.getWeek(entity.getQueryDate());

                return new PieVo(week,entity.getMetricValue());

            }).collect(Collectors.toList());


            pieDataVo.setPie_datas(pieVos);
            pieDataVo.setLegend_datas(pieVos.stream().map(PieVo::getName).collect(Collectors.toList()));
            pieDataVo.setPie_colors(pieVos.stream().map(pie -> WeekType.getColor(pie.getName())).collect(Collectors.toList()));
        }

        return pieDataVo;
    }

    public LineDataVo queryLineDataByType(Long parkId, String startDate, String endDate,String typeId) {
        LineDataVo lineDataVo = new LineDataVo();

        List<MetricEntity> metricEntity = new ArrayList<>();

        if(typeId.equals(ParkMetric.Revenue.getMetricId())){
            metricEntity = parkSummaryMapper.queryRevenue(parkId,startDate,endDate);
            lineDataVo.setTitle(ParkConstant.TITLE_FOR_LINE_REVENUE);
        }else if(typeId.equals(ParkMetric.FLOW.getMetricId())) {
            metricEntity = parkSummaryMapper.queryFlow(parkId,startDate,endDate);
            lineDataVo.setTitle(ParkConstant.TITLE_FOR_LINE_FLOW);
        }else if(typeId.equals(ParkMetric.ORDER.getMetricId())) {
            metricEntity = parkSummaryMapper.queryOrder(parkId,startDate,endDate);
            lineDataVo.setTitle(ParkConstant.TITLE_FOR_LINE_ORDER);
        }

        SerieVo serieVo = new SerieVo();
        serieVo.setName("统计日");
        serieVo.setData(metricEntity.stream().map(entity -> Integer.parseInt(entity.getMetricValue())).collect(Collectors.toList()));

        lineDataVo.setLegend_datas(Arrays.asList("统计日"));
        lineDataVo.setxAxis_data(metricEntity.stream().map(MetricEntity::getQueryDate).collect(Collectors.toList()));
        lineDataVo.setSeries(Arrays.asList(serieVo));

        return lineDataVo;
    }


    @Monitor
    public List<DurationVo> queryDurationReportByDays(Long parkId, String startDate, String endDate, Double duration) throws ParseException {
        Map<Double,String>  map = calc(duration);
        List<DurationVo> durationVos = new ArrayList<>();

        List<DerationData> derationDatas = derationDataMapper.getDerationData(parkId,startDate,endDate);

        // 将数据按天进行分类
        Map<String,List<DerationData>> dateReportData = groupByDay(derationDatas);

        for(String date : dateReportData.keySet()) {
            DurationVo durationVo = new DurationVo();

            Map<Double,Integer> middleDataMap =  calcByDay(dateReportData.get(date),map);

            durationVo.setDate(date);
            durationVo.setReportData(middleDataMap);
            durationVos.add(durationVo);

        }

        System.out.println(durationVos);

        return durationVos;
    }

    public Map<Double,Integer> queryDurationReportByDay(Long parkId, String startDate, String endDate,Double duration) throws ParseException {

        /**
         * 报表规则
         * 1.计算出每条停车记录得秒数
         * 2.按每半个小时得维度来计算数量
         */

        Map<Double,String>  map = calc(duration);

        List<DerationData> derationDatas = derationDataMapper.getDerationData(parkId,startDate,endDate);

        Map<Double,Integer> middleDataMap = calcByDay(derationDatas,map);

        System.out.println("total size:" + derationDatas.size());

        return middleDataMap;
    }

    private Map<String,List<DerationData>> groupByDay(List<DerationData> derationDatas) throws ParseException{

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        for(DerationData data : derationDatas) {
            data.setOutDay(simpleDateFormat.format(simpleDateFormat.parse(data.getOutTime())));
        }

        Map<String,List<DerationData>> dataByDay = derationDatas.stream().collect(Collectors.groupingBy(DerationData::getOutDay,Collectors.toList()));

        return dataByDay;
    }

    private Map<Double,Integer> calcByDay(List<DerationData> derationDatas,Map<Double,String>  map) throws ParseException {
        Map<Double,Integer> middleDataMap = new TreeMap<>();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");

        for(Double key : map.keySet()){
            middleDataMap.put(key,0);
        }

        for(DerationData derationData : derationDatas) {
            Date enterTime = simpleDateFormat.parse(derationData.getInTime());
            Date outerTime = simpleDateFormat.parse(derationData.getOutTime());

            // 相差秒数
            long diff = (outerTime.getTime() - enterTime.getTime()) /1000L;

            for(Double key : map.keySet()){
                String[] values = map.get(key).split(",");

                if(diff >= Long.parseLong(values[0]) && diff <= Long.parseLong(values[1])) {

                    int count = middleDataMap.get(key);
                    middleDataMap.put(key,++count);

                }
            }

        }

        int total = 0;

        for(Double key : middleDataMap.keySet()) {
            int count = middleDataMap.get(key);

            total += count;
        }

        System.out.println("calc size:" + total);

        return middleDataMap;
    }

    public Map<Double,String>  calc(Double duration) {
        Map<Double,String> map = new LinkedHashMap<>();
        int times = (int) (hours / duration);

        for(int i=1 ;i<=times;i++) {
            long start = (long) (one_hour * duration * (i-1)) +1;
            long end = (long) (one_hour * duration * (i));
            map.put(duration * i, start+","+end);
        }
        return map;
    }

    public static void main(String[] args) {
        ReportService reportService = new ReportService();

        reportService.calc(0.5D);

    }
   /**
    * 获取某停车场指定时间区间内每小时进入停车场的车辆数
    * @param startDate
    * @param endDate
    * @param parkId
    * @return
    */
	public Map<Integer, Integer> countParkCarByTimeReport(String startDate, String endDate, Long parkId) {
		Map<Integer, Integer> map = new LinkedHashMap<>();
		for (int i = 0; i < 24; i++) {
			//String strFlag = String.format("%d", i);
			map.put(i, 0);
		}
		try {
			List<ParkCarByTimeVo> list = parkCarByTimeMapper.getCountParkCarByTime(startDate, endDate, parkId);

			if (list == null) {
				return map;
			}
			for (Integer key : map.keySet()) {
				for (ParkCarByTimeVo vo : list) {
					if (key.intValue()==Integer.valueOf(vo.getHour()).intValue()) {
						map.put(key, vo.getAmount());
						break;
					}
				}
			}
		}
		catch (Exception e) {
			System.out.println("countParkCarByTimeReport Exception：" + e.getMessage());
		}
		return map;
	}
}
